home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / lisp / eulisp / mpfeel.lha / MPFeel / specials.c < prev    next >
C/C++ Source or Header  |  1992-10-06  |  24KB  |  1,002 lines

  1. /* ******************************************************************** */
  2. /* specials.c        Copyright (C) Codemist and University of Bath 1989 */
  3. /*                                                                      */
  4. /* Language special forms (NOT toplevel forms)                          */
  5. /* ******************************************************************** */
  6.  
  7. /*
  8.  * $Id: specials.c,v 1.10 1992/03/07 21:45:16 pab Exp $
  9.  *
  10.  * $Log: specials.c,v $
  11.  * Revision 1.10  1992/03/07  21:45:16  pab
  12.  * initial continuation changes
  13.  *
  14.  * Revision 1.9  1992/02/10  16:41:09  pab
  15.  * fixed dynamics properly
  16.  *
  17.  * Revision 1.8  1992/01/29  13:47:28  pab
  18.  * bindig fix, gc fix in dynamic let
  19.  *
  20.  * Revision 1.7  1992/01/09  22:29:05  pab
  21.  * Fixed for low tag ints
  22.  *
  23.  * Revision 1.6  1992/01/07  22:13:27  pab
  24.  * *** empty log message ***
  25.  *
  26.  * Revision 1.5  1992/01/05  22:48:20  pab
  27.  * Minor bug fixes, plus BSD version
  28.  *
  29.  * Revision 1.4  1991/12/22  15:14:34  pab
  30.  * Xmas revision
  31.  *
  32.  * Revision 1.3  1991/09/22  19:14:40  pab
  33.  * Fixed obvious bugs
  34.  *
  35.  * Revision 1.2  1991/09/11  12:07:40  pab
  36.  * 11/9/91 First Alpha release of modified system
  37.  *
  38.  * Revision 1.1  1991/08/12  16:50:00  pab
  39.  * Initial revision
  40.  *
  41.  * Revision 1.4  1991/02/13  18:28:55  kjp
  42.  * Pass.
  43.  *
  44.  */
  45.  
  46. /*
  47.  * Change Log:
  48.  *   Version 1, March 1990 (Compiler rationalisation)
  49.  *     New fully working let/cc and unwind-protect - 
  50.  *       all stacks dealt with and dead continuations killed (KJP)
  51.  */
  52.  
  53. #include "funcalls.h"
  54. #include "defs.h"
  55. #include "structs.h"
  56. #include "error.h"
  57. #include "global.h"
  58.  
  59. #include "funcalls.h"
  60.  
  61. #include "slots.h"
  62. #include "garbage.h"
  63.  
  64. #include "symboot.h"
  65. #include "modules.h"
  66. #include "toplevel.h"
  67. #include "root.h"
  68. #include "allocate.h"
  69. #include "specials.h"
  70. #include "toplevel.h"
  71. #include "state.h"
  72.  
  73. /*
  74.  
  75.  * We're talking just the non-toplevel restricted special forms here
  76.  * like lambda, setq, and if - the ones always available.
  77.  
  78.  */
  79.  
  80. LispObject special_table;
  81.  
  82. LispObject my_make_special(LispObject *stacktop,
  83.                char *name, LispObject (*func)())
  84. {
  85.   LispObject ans,tmp;
  86.  
  87.   ans = (LispObject) get_symbol(stacktop,name);
  88.   STACK_TMP(ans);
  89.   tmp = (LispObject) allocate_special(stacktop,ans,func);
  90.   UNSTACK_TMP(ans);
  91.   ans->SYMBOL.lvalue=tmp;
  92.   STACK_TMP(ans);
  93.   EUCALL_3(tref_updator,special_table,ans,ans->SYMBOL.lvalue);
  94.   UNSTACK_TMP(ans);
  95.   return(ans->SYMBOL.lvalue);
  96. }
  97.  
  98. EUFUN_1( Fn_special_form_p, name)
  99. {
  100.   return(EUCALL_2(Fn_tref,special_table,name));
  101. }
  102. EUFUN_CLOSE
  103.  
  104. LispObject special_lambda;
  105. EUFUN_3( Sf_lambda, mod, env, forms)
  106. {
  107.   LispObject bvl,myforms;
  108.   LispObject ans,walker;
  109.   int i;
  110.  
  111.   if (forms == nil) {
  112.     CallError(stacktop,"lambda: illegal empty lambda form",nil,NONCONTINUABLE);
  113.   }
  114.  
  115.   myforms = forms;
  116.  
  117.   bvl = CAR(myforms); myforms = CDR(myforms);
  118.   STACK_TMP(bvl); STACK_TMP(myforms);
  119.  
  120.   walker = bvl; i = 0;
  121.   while (is_cons(walker)) {
  122.     walker = CDR(walker);
  123.     ++i;
  124.   }
  125.  
  126.   if (walker != nil)  /* improper lambda list */
  127.     ans = (LispObject) allocate_i_function(stacktop,mod,env,-i -1);
  128.   else
  129.     ans = (LispObject) allocate_i_function(stacktop,mod,env,i);
  130.  
  131.   UNSTACK_TMP(myforms); UNSTACK_TMP(bvl);
  132.   ans->I_FUNCTION.bvl  = bvl;
  133.   ans->I_FUNCTION.body = myforms;
  134.   ans->I_FUNCTION.home = ARG_0(stackbase);
  135.  
  136.   return ans;
  137. }
  138. EUFUN_CLOSE
  139.  
  140. LispObject special_macro_lambda;
  141. EUFUN_3(Sf_mlambda, mod, env, forms)
  142. {
  143.   LispObject bvl;
  144.   LispObject ans,walker;
  145.   int i;
  146.  
  147.   if (forms == nil) {
  148.     CallError(stacktop,
  149.           "macro-lambda: illegal empty macro-lambda form",nil,NONCONTINUABLE);
  150.   }
  151.  
  152.   bvl = CAR(forms); forms = CDR(forms);
  153.   ARG_2(stackbase)=forms;
  154.   walker = bvl; i = 0;
  155.   while (is_cons(walker)) {
  156.     walker = CDR(walker);
  157.     ++i;
  158.   }
  159.   STACK_TMP(bvl);
  160.   if (walker != nil)  /* improper lambda list */
  161.     ans = (LispObject) allocate_i_function(stacktop,mod,env,-i -1);
  162.   else
  163.     ans = (LispObject) allocate_i_function(stacktop,mod,env,i);
  164.  
  165.   UNSTACK_TMP(bvl);
  166.   lval_typeof(ans) = TYPE_I_MACRO;
  167.   ans->I_MACRO.bvl  = bvl;
  168.   ans->I_MACRO.body = ARG_2(stackbase)/*forms*/;
  169.   ans->I_MACRO.home = ARG_0(stackbase)/*mod*/;
  170.  
  171.   return ans;
  172. }
  173. EUFUN_CLOSE
  174.  
  175. LispObject special_setq;
  176. EUFUN_3( Sf_setq,  mod, env, forms)
  177. {
  178.   LispObject id;
  179.  
  180.   if (forms == nil) 
  181.     CallError(stacktop,"setq: illegal empty setq form",nil,NONCONTINUABLE);
  182.  
  183.   id = CAR(forms); forms = CDR(forms);
  184.  
  185.   if (!is_symbol(id))
  186.     CallError(stacktop,"setq: non-symbolic id",id,NONCONTINUABLE);
  187.  
  188.   if (CDR(forms)!=nil) 
  189.     CallError(stacktop,"setq: additional setq forms",nil,NONCONTINUABLE);
  190.  
  191.   while (reserved_symbol_p(id)) {
  192.     id = CallError(stacktop,"setq: reserved symbol",id,CONTINUABLE);
  193.   }
  194.   STACK_TMP(id);
  195.   forms = EUCALL_3(module_eval,mod,env,CAR(forms));
  196.   UNSTACK_TMP(id);
  197.   STACK_TMP(forms);
  198.   STACK_TMP(id);
  199.   env=ARG_1(stackbase);
  200.   while (env != NULL) {
  201.     if (env->ENV.variable == id) {
  202.       if (env->ENV.mutable) return (env->ENV.value = forms);
  203.       if (EUCALL_2(Fn_equal, forms, env->ENV.value)==nil) {
  204.     CallError(stacktop,"setq: immutable binding",id,NONCONTINUABLE);
  205.       }
  206.       return forms;
  207.     }
  208.     env = (LispObject) env->ENV.next;
  209.   }
  210.   UNSTACK_TMP(id);
  211.   UNSTACK_TMP(forms);
  212.   /* Going for the module environment */
  213.   mod=ARG_0(stackbase);
  214.   STACK_TMP(forms);
  215.   (void) EUCALL_3(module_set,mod,id,forms); /* In the module handler */
  216.   
  217.   return(forms);
  218.  
  219. }
  220. EUFUN_CLOSE
  221.  
  222. LispObject special_progn;
  223. EUFUN_3( Sf_progn, mod, env, forms)
  224. {
  225.   LispObject ret;
  226.  
  227.   if (!is_cons(forms))
  228.     CallError(stacktop,"progn: bad forms",forms,NONCONTINUABLE);
  229.  
  230.   ret = nil; /* Null case return value */
  231.  
  232.   while (is_cons(forms)) {
  233.     STACK_TMP(CDR(forms));
  234.     ret = EUCALL_3(module_eval,ARG_0(stackbase)/*mod*/,ARG_1(stackbase)/*env*/,CAR(forms));
  235.     UNSTACK_TMP(forms);
  236.   }
  237.  
  238.   return(ret);
  239. }
  240. EUFUN_CLOSE
  241.  
  242. LispObject special_if;
  243. EUFUN_3( Sf_if, mod, env, forms)
  244. {
  245.   LispObject pred,alt1,alt2;
  246.   LispObject debug;
  247.  
  248.   debug = forms;
  249.  
  250.   if (!is_cons(forms))
  251.     CallError(stacktop,"if: missing predicate",forms,NONCONTINUABLE);
  252.  
  253.   pred = CAR(forms); forms = CDR(forms);
  254.  
  255.   if (!is_cons(forms))
  256.     CallError(stacktop,"if: missing consequence",debug,NONCONTINUABLE);
  257.  
  258.   alt1 = CAR(forms); forms = CDR(forms);
  259.  
  260.   if (!is_cons(forms))
  261.     CallError(stacktop,"if: missing alternative",debug,NONCONTINUABLE);
  262.  
  263.   alt2 = CAR(forms); forms = CDR(forms);
  264.  
  265.   if (forms != nil)
  266.     CallError(stacktop,"if: extraneous forms",forms,NONCONTINUABLE);
  267.   
  268.   STACK_TMP(alt1);
  269.   STACK_TMP(alt2);
  270.   if (EUCALL_3(module_eval,mod,env,pred) != nil) {
  271.     UNSTACK_TMP(alt1); UNSTACK_TMP(alt1);
  272.     return(EUCALL_3(module_eval,ARG_0(stackbase)/*mod*/,ARG_1(stackbase)/*env*/,alt1));
  273.   }
  274.   else {
  275.     UNSTACK_TMP(alt2);
  276.     return(EUCALL_3(module_eval,ARG_0(stackbase)/*mod*/,ARG_1(stackbase)/*env*/,alt2));
  277.   }
  278. }
  279. EUFUN_CLOSE
  280.  
  281. /*
  282.  
  283.  * The continuation hacking special forms
  284.  
  285.  */
  286.  
  287. LispObject returned_continue_value;
  288. LispObject last_continue;
  289. LispObject target_continue; /* Used when unwinding... */
  290.  
  291. #define LETCC_DBG(x) /* x;fflush(stdout) */
  292.  
  293. LispObject special_letcc;
  294. EUFUN_3( Sf_letcc, mod, env, forms)
  295. {
  296.   LispObject id;
  297.   LispObject cont;
  298.   LispObject retval;
  299.   
  300.   if (!is_cons(forms))
  301.     CallError(stacktop,"let/cc: weird argument",forms,NONCONTINUABLE);
  302.  
  303.   if (!is_symbol(CAR(forms)))
  304.     CallError(stacktop,"let/cc: non-symbolic continuation name",id,NONCONTINUABLE);
  305.  
  306.   /* OK, now do the business... */
  307.   
  308.   cont = allocate_continue(stacktop);
  309.   STACK_TMP(cont);
  310.  
  311.   if (set_continue(stacktop,cont)) {
  312.  
  313.     /* We were resumed, return the value bit... */
  314.     UNSTACK_TMP(cont);
  315.     return(cont->CONTINUE.value);
  316.  
  317.   }
  318.   UNSTACK_TMP(cont);
  319.   /* The hard bit's done - just add value to env... */
  320.   STACK_TMP(cont);
  321.   
  322.   forms=ARG_2(stackbase);
  323.   id = CAR(forms); forms = CDR(forms);
  324.   
  325.   STACK_TMP(forms);
  326.   env = allocate_envimut(stacktop,id,cont,ARG_1(stackbase));
  327.   UNSTACK_TMP(forms);
  328.   /* retval... */
  329.   
  330.   retval = EUCALL_3(Sf_progn,ARG_0(stackbase)/*mod*/,env,forms);
  331.  
  332.   /* Normal return - kill continuation... */
  333.  
  334.   UNSTACK_TMP(cont);
  335.   unset_continue(cont);
  336.   return(retval);
  337.  
  338. }
  339. EUFUN_CLOSE
  340.   
  341. void call_continuation(LispObject *stacktop,LispObject cont,LispObject value)
  342. {
  343.   LispObject last;
  344.  
  345.   LETCC_DBG(fprintf(stderr,"call cont: continuation invoked\n"));
  346.  
  347.   /* First, check the continuation's still live... */
  348.  
  349.   if (!cont->CONTINUE.live)
  350.     CallError(stacktop,"continuation call: dead continuation",cont,NONCONTINUABLE);
  351.  
  352.   if (cont->CONTINUE.thread != CURRENT_THREAD())
  353.     CallError(stacktop,
  354.           "continuation call: not on this thread",cont,NONCONTINUABLE);
  355.  
  356.   /* That's cool, now wander down (up?) the dynamic continuation list
  357.              killing stuff off and looking for unwind protects        */
  358.  
  359.   last = SYSTEM_THREAD_SPECIFIC_VALUE(state_last_continue);
  360.  
  361.   while (last != cont) {
  362.  
  363.     if (last == nil) {
  364.       fprintf(stderr,"AARRRRGGHHH!!!: continuation vanished!");
  365.       exit(1);
  366.     }
  367.  
  368.     if (last->CONTINUE.unwind) {
  369.       LispObject temp;
  370.  
  371.       /* We have an unwind continuation */
  372.  
  373.       /* Leave interesting info for unwind-protect */
  374.  
  375.       last->CONTINUE.target = cont;
  376.       last->CONTINUE.value = value;
  377.  
  378.       /* Kill this unwind continuation */
  379.  
  380.       temp = last;
  381.       last 
  382.     = SYSTEM_THREAD_SPECIFIC_VALUE(state_last_continue) 
  383.       = temp->CONTINUE.last_continue;
  384.  
  385.       /* Jump... */
  386.  
  387.       call_continue(stacktop,temp,value);
  388.  
  389.     }
  390.  
  391.     /* Normal continuation - kill it ! */
  392.  
  393. LETCC_DBG(fprintf(stderr,"call cont: killing middle continue\n"));
  394.  
  395.     {
  396.       LispObject temp;
  397.  
  398.       temp = last->CONTINUE.last_continue;
  399.       last->CONTINUE.live = FALSE;
  400.       last->CONTINUE.last_continue = nil;
  401.       last = SYSTEM_THREAD_SPECIFIC_VALUE(state_last_continue) = temp;
  402.  
  403.     }
  404.  
  405.   }
  406.  
  407. LETCC_DBG(fprintf(stderr,"call cont: hacking world\n"));
  408.  
  409.   /* We've hit our own, so all is hunkydory */
  410.  
  411.   /* Jump away... */
  412.  
  413.   call_continue(stacktop,cont,value);
  414.  
  415.  
  416. LispObject special_unwind_protect; 
  417. EUFUN_3( Sf_unwind_protect, mod, env, forms)
  418. {
  419.   LispObject protected_form;
  420.   LispObject cont,value;
  421.  
  422.   if (!is_cons(forms))
  423.     CallError(stacktop,"unwind-protect: invalid null argument",nil,NONCONTINUABLE);
  424.  
  425.   protected_form = CAR(forms);
  426.  
  427.   /* OK, want to set up an unwind marker */
  428.  
  429.   cont = allocate_continue(stacktop); /* Allocate and freeze */
  430.   STACK_TMP(cont);
  431.   if (set_continue(stacktop,cont)) {
  432.     
  433.     /* We've been invoked - run the tidy up forms... */
  434.  
  435.     (void) EUCALL_3(Sf_progn,ARG_0(stackbase)/*mod*/,ARG_1(stackbase)/*env*/,
  436.             CDR(ARG_2(stackbase))/* unwind_forms*/);
  437.  
  438.     /* Got through that succesfully, so now try and find the target... */
  439.     UNSTACK_TMP(cont);
  440.     call_continuation(stacktop,cont->CONTINUE.target,cont->CONTINUE.value);
  441.  
  442.   }
  443.  
  444.   /* Mark the continuation as an unwind protect thing */
  445.   cont->CONTINUE.unwind = TRUE;
  446.   
  447.   value = EUCALL_3(module_eval,ARG_0(stackbase),ARG_1(stackbase),CAR(ARG_2(stackbase)));
  448.   
  449.   /* Kill off the continuation */
  450.   UNSTACK_TMP(cont);
  451.  
  452.   unset_continue(cont);
  453.  
  454.   /* Process the outward forms */
  455.  
  456.   STACK_TMP(value);
  457.   (void) EUCALL_3(Sf_progn,ARG_0(stackbase),ARG_1(stackbase),CDR(ARG_2(stackbase)));
  458.   UNSTACK_TMP(value);
  459.   return(value);
  460.  
  461. }
  462. EUFUN_CLOSE
  463. /*
  464.  
  465.  * Dynamics...
  466.  
  467.  */
  468.  
  469. LispObject special_dynamic_setq;
  470. EUFUN_3( Sf_dynamic_setq, mod, env, forms)
  471. {
  472.   LispObject id,form;
  473.   Env walker;
  474.  
  475.   if (!is_cons(forms))
  476.     CallError(stacktop,"dynamic-setq: missing symbol",forms,NONCONTINUABLE);
  477.  
  478.   id = CAR(forms); forms = CDR(forms);
  479.  
  480.   if (!is_symbol(id))
  481.     CallError(stacktop,"dynamic-setq: non-symbolic reference",id,NONCONTINUABLE);
  482.  
  483.   if (!is_cons(forms)) 
  484.     CallError(stacktop,"dynamic-setq: missing value form",forms,NONCONTINUABLE);
  485.  
  486.   form = CAR(forms); forms = CDR(forms);
  487.  
  488.   if (forms != nil)
  489.     CallError(stacktop,"dynamic-setq: extraneous forms",forms,NONCONTINUABLE);
  490.  
  491.   walker = DYNAMIC_ENV();
  492.  
  493.   while (walker != NULL) {
  494.     if (walker->variable == id)
  495.       {
  496.     STACK_TMP(walker);
  497.     form = EUCALL_3(module_eval,mod,env,form);
  498.     UNSTACK_TMP(walker);
  499.     return((walker->value = form));
  500.       }
  501.     walker = walker->next;
  502.   }
  503.  
  504.   if (id->SYMBOL.gvalue == NULL) {
  505.     fprintf(stderr,"****Illegal assignment to undeclared variable: ");
  506.     EUCALL_2(Fn_print,id,StdErr);
  507.     fprintf(stderr,"****Implicit defvar used\n");
  508.   }
  509.   STACK_TMP(id);
  510.   form = EUCALL_3(module_eval,mod,env,form);
  511.   UNSTACK_TMP(id);
  512.   return((id->SYMBOL.gvalue = form));
  513. }
  514. EUFUN_CLOSE
  515.  
  516. EUFUN_2( Fn_dynamic_setq, id, form)
  517. {
  518.   Env walker;
  519.  
  520.   if (!is_symbol(id))
  521.     CallError(stacktop,"(setter symbol-dynamic-value): non-symbolic reference",id,NONCONTINUABLE);
  522.  
  523.   walker = DYNAMIC_ENV();
  524.  
  525.   while (walker != NULL) {
  526.     if (walker->variable == id) return((walker->value = form));
  527.     walker = walker->next;
  528.   }
  529.  
  530.   if (id->SYMBOL.gvalue == NULL) {
  531.     fprintf(stderr,"****Illegal assignment to undeclared variable: ");
  532.     EUCALL_2(Fn_print,id,StdErr);
  533.     fprintf(stderr,"****Implicit defvar used\n");
  534.   }
  535.  
  536.   return((id->SYMBOL.gvalue = form));
  537. }
  538. EUFUN_CLOSE
  539.  
  540. LispObject special_dynamic_set;
  541. EUFUN_3( Sf_dynamic_set, mod, env, forms)
  542. {
  543.   LispObject id,form;
  544.   Env walker;
  545.  
  546.   if (!is_cons(forms))
  547.     CallError(stacktop,"dynamic-set: missing symbol",forms,NONCONTINUABLE);
  548.  
  549.   id = CAR(forms); forms = CDR(forms);
  550.  
  551.   id = EUCALL_3(module_eval,mod,env,id);
  552.  
  553.   if (!is_symbol(id))
  554.     CallError(stacktop,"dynamic-set: non-symbolic reference",id,NONCONTINUABLE);
  555.  
  556.   if (!is_cons(forms)) 
  557.     CallError(stacktop,"dynamic-set: missing value form",forms,NONCONTINUABLE);
  558.  
  559.   form = CAR(forms); forms = CDR(forms);
  560.  
  561.   if (forms != nil)
  562.     CallError(stacktop,"dynamic-set: extraneous forms",forms,NONCONTINUABLE);
  563.  
  564.   STACK_TMP(id);
  565.   form = EUCALL_3(module_eval,mod,env,form);
  566.   UNSTACK_TMP(id);
  567.   walker = DYNAMIC_ENV();
  568.  
  569.   while (walker != NULL) {
  570.     if (walker->variable == id) return((walker->value = form));
  571.     walker = walker->next;
  572.   }
  573.  
  574.   if (id->SYMBOL.gvalue == NULL) {
  575.     fprintf(stderr,"****Illegal assignment to undeclared variable: ");
  576.     EUCALL_2(Fn_print,id,StdErr);
  577.     fprintf(stderr,"****Implicit defvar used\n");
  578.   }
  579.  
  580.   return((id->SYMBOL.gvalue = form));
  581. }
  582. EUFUN_CLOSE
  583.  
  584. LispObject special_dynamic_let;
  585. EUFUN_3( Sf_dynamic_let, mod, env, forms)
  586. {
  587.   LispObject bindings;
  588.   Env save;
  589.  
  590.   if (!is_cons(forms))
  591.     CallError(stacktop,"dynamic-let: null forms",forms,NONCONTINUABLE);
  592.  
  593.   bindings = CAR(forms); forms = CDR(forms);
  594.  
  595.   if (!is_cons(bindings)) 
  596.     CallError(stacktop,
  597.           "dynamic-let: invalid binding forms",bindings,NONCONTINUABLE);
  598.  
  599.   save = DYNAMIC_ENV(); /* Hang on for exit... */
  600.   
  601.   STACK_TMP(forms); 
  602.   STACK_TMP(save);
  603.   while (is_cons(bindings)) {
  604.     LispObject id,val,bind;
  605.     LispObject xx;
  606.  
  607.     bind = CAR(bindings);
  608.     STACK_TMP(CDR(bindings));
  609.     if (!is_cons(bind))
  610.       CallError(stacktop,
  611.         "dynamic-let: weird binding",bindings,NONCONTINUABLE);
  612.  
  613.     id = CAR(bind); bind = CDR(bind);
  614.  
  615.     if (!is_symbol(id)) 
  616.       CallError(stacktop,"dynamic-let: non-symbolic var",id,NONCONTINUABLE);
  617.  
  618.     if (!is_cons(bind))
  619.       CallError(stacktop,"dynamic-let: weird binding",bindings,NONCONTINUABLE);
  620.  
  621.     val = CAR(bind);
  622.  
  623.     STACK_TMP(id);
  624.     val = EUCALL_3(module_eval,ARG_0(stackbase),ARG_1(stackbase),val);
  625.     UNSTACK_TMP(id);
  626.  
  627.     xx = &(allocate_env(stacktop,id,val,
  628.             (LispObject)DYNAMIC_ENV())->ENV);    
  629.     DYNAMIC_ENV()=xx;
  630.     UNSTACK_TMP(bindings);
  631.   }
  632.   UNSTACK_TMP(save);
  633.   UNSTACK_TMP(forms);
  634.   /* Do body... */
  635.  
  636.   forms = EUCALL_3(Sf_progn,ARG_0(stackbase),ARG_1(stackbase),forms);
  637.  
  638.   DYNAMIC_ENV() = save; /* Repoint */
  639.  
  640.   return(forms);
  641. }
  642. EUFUN_CLOSE    
  643.  
  644. EUFUN_1( Fn_dynamic, form)
  645. {
  646.   {
  647.     Env ee = DYNAMIC_ENV();
  648.     while (ee!=NULL) {
  649.       if (ee->variable == form) return ee->value;
  650.       ee = ee->next;
  651.     }
  652.   }
  653.   {
  654.     LispObject ans;
  655.     ans =  (form->SYMBOL).gvalue;
  656.     if (ans==NULL) {        /* signal UNBOUND_DYNAMIC_VARIABLE */
  657.       ans = CallError(stacktop,"Unset dynamic variable ",form,CONTINUABLE);
  658.       (form->SYMBOL).gvalue = ans;
  659.     }
  660.     return ans;
  661.   }
  662. }
  663. EUFUN_CLOSE
  664.  
  665. LispObject special_dynamic;
  666. EUFUN_3( Sf_dynamic, mod, env, form)
  667. {
  668.   IGNORE(mod); IGNORE(env);
  669.  
  670.   while (!is_symbol(CAR(form)) || CDR(form)!=nil)
  671.     form = CallError(stacktop,"dynamic: Illegal dynamic form ",form,CONTINUABLE);
  672.  
  673.   form = CAR(form);
  674.  
  675.   {
  676.     Env ee = DYNAMIC_ENV();
  677.     while (ee!=NULL) {
  678.       if (ee->variable == form) return ee->value;
  679.       ee = ee->next;
  680.     }
  681.   }
  682.   {
  683.     LispObject ans;
  684.     ans =  (form->SYMBOL).gvalue;
  685.     if (ans==NULL) {        /* signal UNBOUND_DYNAMIC_VARIABLE */
  686.       ans = CallError(stacktop,"dynamic: unset dynamic variable ",form,CONTINUABLE);
  687.       (form->SYMBOL).gvalue = ans;
  688.     }
  689.     return ans;
  690.   }
  691. }
  692. EUFUN_CLOSE
  693.  
  694. LispObject special_quote;
  695. EUFUN_3( Sf_quote, mod, env, forms)
  696. {
  697.   IGNORE(mod); IGNORE(env);
  698.  
  699.   if (!is_cons(forms))
  700.     CallError(stacktop,"quote: bad forms",forms,NONCONTINUABLE);
  701.  
  702.   return(CAR(forms));
  703. }
  704. EUFUN_CLOSE
  705.  
  706. /*
  707.  
  708.  * Handlers...
  709.  
  710.  */
  711.  
  712. LispObject special_with_handler;
  713. EUFUN_3( Sf_with_handler, mod, env, forms)
  714. {
  715.   LispObject handler;
  716.   LispObject retval;
  717.   
  718.   if (!is_cons(forms))
  719.     CallError(stacktop,
  720.           "with-handler: missing handler function",forms,NONCONTINUABLE);
  721.  
  722.   handler = CAR(forms);
  723.  
  724.   handler = EUCALL_3(module_eval,mod,env,handler);
  725.   
  726.   if (!is_function(handler))
  727.     CallError(stacktop,
  728.           "with-handler: non-functional handler",handler,NONCONTINUABLE);
  729.  
  730.   /* So far, so good - bung this onto the handler stack... */
  731.  
  732.   HANDLER_STACK() = EUCALL_2(Fn_cons,handler,HANDLER_STACK());
  733.  
  734.   /* Process the forms... */
  735.  
  736.   retval = EUCALL_3(Sf_progn,ARG_0(stackbase)/*mod*/,ARG_1(stackbase)/*env*/,CDR(ARG_2(stackbase)));
  737.  
  738.   /* Unhitch the handler... */
  739.  
  740.   HANDLER_STACK() = CDR(HANDLER_STACK());
  741.  
  742.   return(retval);
  743. }
  744. EUFUN_CLOSE
  745.  
  746. /*******    
  747.  * modified handler interactions
  748.  *
  749.  *******/
  750.  
  751. EUFUN_1(Fn_push_handler,handler)
  752. {
  753.   HANDLER_STACK() = EUCALL_2(Fn_cons,handler,HANDLER_STACK());
  754.   
  755.   return (HANDLER_STACK());
  756. }
  757. EUFUN_CLOSE
  758.  
  759. EUFUN_0(Fn_pop_handler)
  760. {
  761.   HANDLER_STACK() = CDR(HANDLER_STACK());
  762.   
  763.   return HANDLER_STACK();
  764. }
  765. EUFUN_CLOSE
  766.  
  767. /* I'll never write a complicated one (in C) */
  768. EUFUN_1(Fn_simple_call_cc,fn)
  769. {
  770.   LispObject cont;
  771.   LispObject args;
  772.   cont=allocate_continue(stacktop);
  773.   
  774.   STACK_TMP(cont);
  775.  
  776.   if (set_continue(stacktop,cont))
  777.     {    /* forcible return */
  778.       UNSTACK_TMP(cont);
  779.       return(cont->CONTINUE.value);
  780.     }
  781.  
  782.   UNSTACK_TMP(cont);
  783.   STACK_TMP(cont);
  784.   args=EUCALL_2(Fn_cons,cont,nil);
  785.   
  786.   return(EUCALL_2(module_mv_apply_1,ARG_0(stackbase)/*fn*/,args));
  787.  
  788. }
  789. EUFUN_CLOSE
  790.  
  791. /* Hack... */
  792.  
  793. LispObject special_evalcm;
  794. EUFUN_3(Sf_evalcm, mod, env, form)
  795. {
  796.   LispObject ans;
  797.  
  798.   if (!is_cons(form))
  799.     CallError(stacktop,"eval/cm: no arguments",form,NONCONTINUABLE);
  800.  
  801.   if (is_cons(CDR(form)))
  802.     CallError(stacktop,"eval/cm: too many arguments",form,NONCONTINUABLE);
  803.  
  804.   form = EUCALL_3(module_eval,mod,env,form);
  805.  
  806.   ans = EUCALL_2(process_top_level_form,mod,CAR(form));
  807.  
  808.   return(ans);
  809. }
  810. EUFUN_CLOSE
  811.  
  812. /* Tag Body... */
  813.  
  814. /*
  815.  
  816.  * 'tagbody'
  817.  *
  818.  *   Plan: Do a naive walk on the body to extract a table of symbols with
  819.  *         following code, rig a continuation for 'go' statements to jump
  820.  *         to and run them in sequence until done...
  821.  
  822.  */
  823.  
  824. /* ******************** This function cannot be called *************** */
  825. static LispObject tagbody_before_label(LispObject *stacktop,LispObject body)
  826. {
  827.   if (!is_cons(body)) return(nil);
  828.   if (is_symbol(CAR(body))) return(nil);
  829.  
  830.   return(EUCALL_2(Fn_cons,CAR(body),tagbody_before_label(stacktop,CDR(body))));
  831. }
  832.  
  833. static LispObject tagbody_suck_symbols(LispObject *stacktop,LispObject body)
  834. {
  835.   if (!is_cons(body)) return(nil);
  836.   if (is_symbol(CAR(body))) return(tagbody_suck_symbols(stacktop,CDR(body)));
  837.  
  838.   return(EUCALL_2(Fn_cons,CAR(body),tagbody_suck_symbols(stacktop,CDR(body))));
  839. }
  840.  
  841. static LispObject tagbody_handle;
  842.  
  843. LispObject special_tagbody;
  844. EUFUN_3( Sf_tagbody, mod, env, forms)
  845. {
  846.   LispObject table,cont;
  847.   LispObject walker;
  848.   LispObject before;
  849.   LispObject res;
  850.  
  851.   table = (LispObject) allocate_table(stacktop,Fn_eq);
  852.   STACK_TMP(table);
  853.   before = nil;
  854.   before = tagbody_suck_symbols(stacktop,forms);
  855.   STACK_TMP(before);
  856.  
  857.   walker = forms;
  858.   while (is_cons(walker)) {
  859.     if (is_symbol(CAR(walker))) break;
  860.     walker = CDR(walker);
  861.   }
  862.  
  863.   if (is_cons(walker)) {
  864.     Env augenv;
  865.     LispObject runbody;
  866.  
  867.     /* Non-trivial label forms... */
  868.  
  869.     cont = allocate_continue(stacktop);
  870.     STACK_TMP(cont);
  871.  
  872.     do {
  873.       LispObject label, body;
  874.  
  875.       label = CAR(walker); walker = CDR(walker);
  876.       body = tagbody_suck_symbols(stacktop,walker);
  877.       EUCALL_3(tref_updator,table,label,body);
  878.  
  879.       while (is_cons(walker)) {
  880.     if (is_symbol(CAR(walker))) break;
  881.     walker = CDR(walker);
  882.       }
  883.     } while (is_cons(walker));
  884.  
  885.     /* Construct the augmented environment... */
  886.  
  887.     UNSTACK_TMP(cont);
  888.     augenv = (Env)allocate_env(stacktop,tagbody_handle,cont,env);
  889.     STACK_TMPV(augenv);
  890.  
  891.     runbody = before;
  892.  
  893.    reset:
  894.  
  895.     /* Go continuation... */
  896.  
  897.     if (set_continue(stacktop,cont)) {
  898.  
  899.       /* Go has been called... */
  900.  
  901.       runbody = EUCALL_2(Fn_tref,table,cont->CONTINUE.value);
  902.  
  903.       if (runbody == nil)
  904.     CallError(stacktop,
  905.           "go: no such label",cont->CONTINUE.value,NONCONTINUABLE);
  906.  
  907.       goto reset;
  908.     }
  909.  
  910.     UNSTACK_TMPV(augenv);
  911.     
  912.     STACK_TMP(cont);
  913.     res = EUCALL_3(Sf_progn,mod,(LispObject)augenv,runbody);
  914.     UNSTACK_TMP(cont);
  915.     unset_continue(cont);
  916.  
  917.     return(res);
  918.   }
  919.  
  920.   res = EUCALL_3(Sf_progn,mod,env,before);
  921.  
  922.   return(res);
  923. }
  924. EUFUN_CLOSE
  925.  
  926. LispObject special_go;
  927. EUFUN_3( Sf_go, mod, env, forms)
  928. {
  929.   LispObject tag;
  930.   Env walker;
  931.  
  932.   IGNORE(mod);
  933.  
  934.   if (!is_cons(forms))
  935.     CallError(stacktop,"go: no tag",forms,NONCONTINUABLE);
  936.  
  937.   tag = CAR(forms);
  938.  
  939.   if (!is_symbol(tag))
  940.     CallError(stacktop,"go: non-symbolic tag",tag,NONCONTINUABLE);
  941.  
  942.   walker = (Env)env;
  943.   while (walker != NULL) {
  944.     if (walker->variable == tagbody_handle)
  945.       call_continue(stacktop,walker->value,tag);
  946.     walker = walker->next;
  947.   }
  948.  
  949.   CallError(stacktop,"go: not within tagbody",nil,NONCONTINUABLE);
  950.  
  951.   return(nil);
  952. }
  953. EUFUN_CLOSE
  954.  
  955. void initialise_specials(LispObject *stacktop)
  956. {
  957.   special_table = (LispObject) allocate_table(stacktop,Fn_eq);
  958.   add_root(&special_table);
  959.   
  960.   special_lambda = my_make_special(stacktop,"lambda",Sf_lambda);
  961.   add_root(&special_lambda);
  962.   special_macro_lambda = my_make_special(stacktop,"macro-lambda",Sf_mlambda);
  963.   add_root(&special_macro_lambda);
  964.   special_setq   = my_make_special(stacktop,"setq",Sf_setq);
  965.   add_root(&special_setq);
  966.   special_progn  = my_make_special(stacktop,"progn",Sf_progn);
  967.   add_root(&special_progn);
  968.   special_if     = my_make_special(stacktop,"if",Sf_if);
  969.   add_root(&special_if);
  970.   
  971.   special_letcc  = my_make_special(stacktop,"let/cc",Sf_letcc);
  972.   add_root(&special_letcc);
  973.   special_unwind_protect = my_make_special(stacktop,"unwind-protect",Sf_unwind_protect);
  974.   add_root(&special_unwind_protect);
  975.   
  976. /*  last_continue = nil;*/
  977.  
  978.   special_dynamic_setq = my_make_special(stacktop,"dynamic-setq",Sf_dynamic_setq);
  979.   add_root(&special_dynamic_setq);
  980.   special_dynamic_set  = my_make_special(stacktop,"dynamic-set",Sf_dynamic_set);
  981.   add_root(&special_dynamic_set);
  982.   special_dynamic_let  = my_make_special(stacktop,"dynamic-let",Sf_dynamic_let);
  983.   add_root(&special_dynamic_let);
  984.   special_dynamic      = my_make_special(stacktop,"dynamic",Sf_dynamic);
  985.   add_root(&special_dynamic_let);
  986.   
  987.   special_quote = my_make_special(stacktop,"quote",Sf_quote);
  988.   add_root(&special_quote);
  989.   
  990.   special_with_handler = my_make_special(stacktop,"with-handler",Sf_with_handler);
  991.   add_root(&special_with_handler);
  992.   
  993.   special_tagbody = my_make_special(stacktop,"tagbody",Sf_tagbody);
  994.   add_root(&special_tagbody);
  995.   tagbody_handle = get_symbol(stacktop,"***tagbody-handle***");
  996.   add_root(&tagbody_handle);
  997.   special_go = my_make_special(stacktop,"go",Sf_go);
  998.   add_root(&special_go);
  999. }
  1000.  
  1001.